﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace BadHabit.Factory.Controls {

    /// <summary>
    /// Base class for the post it grid and task datagrid.
    /// </summary>
    public class TaskViewerBase : UserControl {

        // this is a key for the BacklogItemFilter property
        internal static readonly DependencyProperty BacklogItemFilterProperty =
            DependencyProperty.Register("BacklogItemFilter", typeof(System.Data.DataRowView), typeof(TaskViewerBase), new PropertyMetadata(new PropertyChangedCallback(OnFilterChanged)));

        // this is a key for the TaskSearchFilter property
        internal static readonly DependencyProperty TaskSearchFilterProperty =
            DependencyProperty.Register("TaskSearchFilter", typeof(String), typeof(TaskViewerBase), new PropertyMetadata(new PropertyChangedCallback(OnFilterChanged)));

        // this is a key for the TaskBugFilter property
        internal static readonly DependencyProperty TaskBugOnlyFilterProperty =
            DependencyProperty.Register("TaskBugOnlyFilter", typeof(bool), typeof(TaskViewerBase), new PropertyMetadata(new PropertyChangedCallback(OnFilterChanged)));

        // this is a key for the TaskImpedimentFilter property
        internal static readonly DependencyProperty TaskImpedimentOnlyFilterProperty =
            DependencyProperty.Register("TaskImpedimentOnlyFilter", typeof(bool), typeof(TaskViewerBase), new PropertyMetadata(new PropertyChangedCallback(OnFilterChanged)));

        // this is a key for the Task SearchFilter property
        internal static readonly DependencyProperty TaskStatusFilterProperty =
            DependencyProperty.Register("TaskStatusFilter", typeof(TaskStatus), typeof(TaskViewerBase), new PropertyMetadata(new PropertyChangedCallback(OnFilterChanged)));
    
        
        // this is a key for the TaskCount property
        internal static readonly DependencyPropertyKey TaskCountKey =
            DependencyProperty.RegisterReadOnly("TaskCount", typeof(int), typeof(TaskViewerBase), new PropertyMetadata(null));
        public static readonly DependencyProperty TaskCountProperty = TaskCountKey.DependencyProperty;

        // this is a key for the TaskHourCount property
        internal static readonly DependencyPropertyKey TaskHourCountKey =
            DependencyProperty.RegisterReadOnly("TaskHourCount", typeof(double), typeof(TaskViewerBase), new PropertyMetadata(null));
        public static readonly DependencyProperty TaskHourProperty = TaskHourCountKey.DependencyProperty;



        
        internal string FilterString {
            get {

                string filter = "(1=1)";

                // Backlog Item filter
                if (BacklogItemFilter != null) 
                    filter = filter + " AND (BacklogItemUId='" + BacklogItemFilter["BacklogItemUId"] + "' AND SprintUId='" + BacklogItemFilter["SprintUId"] + "')";
                

                // Bug filter
                if (TaskBugOnlyFilter == true) 
                    filter = filter + " AND (TaskType=" + (short) TaskTypes.DEVELOPING_BUG + " or TaskType=" + (short) TaskTypes.AFTER_DELIVERY_BUG + ")";
                
                // Impediment filter
                if (TaskImpedimentOnlyFilter == true)
                    filter = filter + " AND (TaskType=" + (short)TaskTypes.IMPEDIMENT + ")";

                // Text Filter
                if (TaskSearchFilter != null) {
                    int intTaskId;
                    string taskIdFilter = "";
                    if (Int32.TryParse(TaskSearchFilter, out intTaskId)) {
                        taskIdFilter = " OR TaskId=" + TaskSearchFilter;
                    }
                    filter = filter + " AND (TaskName LIKE '%" + TaskSearchFilter + "%' OR TaskId < 0 OR TaskAssignee LIKE '%" + TaskSearchFilter + "%'" + taskIdFilter + ")";
                }


                return filter;
            }
        }


        

        /// <summary>
        /// Gets the number of tasks after the filter is applied.
        /// This is a DependencyProperty.
        /// </summary>
        public int TaskCount {
            get {
                return (int)GetValue(TaskCountProperty);
            }
        }

        /// <summary>
        /// Gets the number of hours tasks after the filter is applied.
        /// This is a DependencyProperty.
        /// </summary>
        public double TaskHour {
            get {
                return (double)GetValue(TaskHourProperty);
            }
        }
       


        /// <summary>
        /// Gets and Sets the Task Status Filter.
        /// </summary>       
        public TaskStatus TaskStatusFilter {
            get { return (TaskStatus)GetValue(TaskStatusFilterProperty); }
            set { SetValue(TaskStatusFilterProperty, value); }
        }

        /// <summary>
        /// Gets and Sets the TaskSearchFilter.
        /// </summary>       
        public String TaskSearchFilter {
            get { return (String)GetValue(TaskSearchFilterProperty); }
            set { SetValue(TaskSearchFilterProperty, value); }
        }

        /// <summary>
        /// Gets and Sets the TaskBugOnlyFilter.
        /// </summary>       
        public bool TaskBugOnlyFilter {
            get { return (bool)GetValue(TaskBugOnlyFilterProperty); }
            set { SetValue(TaskBugOnlyFilterProperty, value); }
        }

        /// <summary>
        /// Gets and Sets the TaskImpedimentOnlyFilter.
        /// </summary>       
        public bool TaskImpedimentOnlyFilter {
            get { return (bool)GetValue(TaskImpedimentOnlyFilterProperty); }
            set { SetValue(TaskImpedimentOnlyFilterProperty, value); }
        }

        /// <summary>
        /// Gets and Sets the BacklogItemFilter.
        /// </summary>       
        public System.Data.DataRowView BacklogItemFilter {
            get { return (System.Data.DataRowView)GetValue(BacklogItemFilterProperty); }
            set { SetValue(BacklogItemFilterProperty, value); }
        }


        /// <summary>
        /// If any filter has changed, applies it.
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            TaskViewerBase taskViewer = d as TaskViewerBase;
            taskViewer.AllowAddTask = (taskViewer.BacklogItemFilter != null);                            
            taskViewer.ApplyFilter();
        }


        protected virtual void ApplyFilter() {
        }

        protected virtual bool AllowAddTask {
            set {
            }
        }
      
        /// <summary>
        /// Sets the defualt values for a new task.
        /// </summary>
        /// <param name="newTask">The new task row</param>
        protected void SetDefaultTaskValues(Data.TaskDataSet.TaskRow newTask) {            

            newTask.ProjectUId = BacklogItemFilter["ProjectUId"].ToString().ToLower();
            newTask.BacklogItemUId = BacklogItemFilter["BacklogItemUId"].ToString().ToLower();
            newTask.BacklogItemNumber = (short) BacklogItemFilter["BacklogItemNumber"];
            newTask.SprintUId = BacklogItemFilter["SprintUId"].ToString().ToLower();


            newTask.TaskUId = Guid.NewGuid().ToString().ToLower();
            
            newTask.TaskType = (short)TaskTypes.PROJECT_TASK;
            newTask.TaskOwner = Client.User.Identity.Name;
            newTask.Status = (short)BadHabit.Factory.TaskStatus.TASK_REQUIRED;
            newTask.CreateDate = DateTime.Now;
            newTask.Priority = (short)2;
            newTask.PercentComplete = 0;
            newTask.Duration = 0;
            newTask.PlannedEffort = (double)0;
            newTask.ActualEffort = (double)0;
            newTask.Payable = true;

            newTask.PlannedStart = DateTime.Now;
            newTask.PlannedFinish = DateTime.Now.AddHours(8);

            // is is not a scrum master user can only create tasks for him self
            if(! Converters.IsReadOnlyTaskConverter.CanEditOtherTasks) {
                newTask.TaskAssignee = Client.User.Identity.Name;
            }

            
        }


        /// <summary>
        /// Updates the task unitName according the task assigned.
        /// </summary>
        /// <param name="combo">The task assignee combobox</param>
        protected void UpdateTaskUnitNameByMember(object sender, SelectionChangedEventArgs e) {

            // first find the task we are talking about
            ComboBox combo = sender as ComboBox;
            if (combo == null)
                return;            
                        
            Data.TaskDataSet.TaskRow task = Helper.GetRowFromRowView<Data.TaskDataSet.TaskRow>(combo.DataContext);
            if (task == null)
                return;

            // if this is not a user, change, and its just a SelectionChange from the first bind of the control
            // get out of my lucky face
            if (task.RowState == System.Data.DataRowState.Unchanged)
                return;

            // now gets the unit for the member            
            Data.TeamDataSet.MemberRow member = Helper.GetRowFromRowView<Data.TeamDataSet.MemberRow>(combo.SelectedItem);
            if (member == null)
                return;

            // finally sets the task unit
            if(!task["UnitName"].ToString().Equals(member.DefaultUnitName))
                task["UnitName"] = member.DefaultUnitName;

        }


        public virtual void PasteTasks(String[] tasks) {}


        protected bool CanAddTask() {
            // if no backlog item is selected, get out
            if (BacklogItemFilter == null) {
                BadHabit.Factory.Windows.Error.ShowAlert("Please, select a Backlog Item to create a new task.");
                return false;
            }

            // if is not a scrum master and is not at the project can not add a task
            if (!Converters.IsReadOnlyTaskConverter.CanEditOtherTasks && !Client.IsUserAtProject) {
                BadHabit.Factory.Windows.Error.ShowAlert("You are not a member of this project.\nYou need to be a project member to add a new task.");
                return false;
            }

            return true;
        }




        protected bool VerifyTaskChangePermission(Data.TaskDataSet.TaskRow task) {
            if (!Converters.IsReadOnlyTaskConverter.CanEditThisTask(task)) {
                Windows.Error.ShowAlert("You can not change other members tasks.");
                return false;
            }
            return true;
        }

        protected bool VerifyAddTaskMaterial(Data.TaskDataSet.TaskRow task) {
            if (task.RowState==System.Data.DataRowState.Added) {
                Windows.Error.ShowAlert("You need to commit a task first in order to add material to it.");
                return false;
            }
            return true;
        }


        public static void AddTaskMaterial(string taskUId, string projectDocFolder, string[] materialPath, bool asLink) {
            // if is not a link copy the file to Material folder of the project
            if (!asLink) {
                try {
                    materialPath = CopyMaterial(projectDocFolder, materialPath);
                } catch (Exception) {
                    Windows.Error.ShowAlert("Sorry, could not copy material to folder '" + projectDocFolder + "'");
                    return;
                }
            }

            try {
                Client.Service.TailTaskMaterialAsLink(taskUId, materialPath);
            } catch (Exception ex) {
                Windows.Error.ShowError(ex, "Sorry could not add material to project");
            }            
        }
        
        public static void AddTaskMaterial(string taskUId, string projectDocFolder, bool asLink) {

            if (DBNull.Value.Equals(projectDocFolder) || String.IsNullOrEmpty(projectDocFolder)) {
                Windows.Error.ShowAlert("Project does not have a network folder to copy material to.");
                return;
            }

            System.Windows.Forms.OpenFileDialog openDialog = new System.Windows.Forms.OpenFileDialog();
            openDialog.Title = "Add Task Material";
            openDialog.Multiselect = true;
            System.Windows.Forms.DialogResult d = openDialog.ShowDialog();
            if (d == System.Windows.Forms.DialogResult.Cancel)
                return;
            string[] materialPath = openDialog.FileNames;
            if (materialPath == null || materialPath.Length == 0)
                return;

            AddTaskMaterial(taskUId, projectDocFolder, materialPath, asLink);
            

        }

        private static string[] CopyMaterial(string projectDocFolder, string[] materialPath) {
            string[] networkPath = new string[materialPath.Length];
            for (int i = 0; i < networkPath.Length; i++) {
                string fileName = GetArtifactName(materialPath[i]);
                string netPath = projectDocFolder + "\\Material";
                networkPath[i] = MountNetworkPath(netPath, fileName);
                if (!System.IO.Directory.Exists(netPath))
                    System.IO.Directory.CreateDirectory(netPath); 

                System.IO.File.Copy(materialPath[i], networkPath[i], true);
            }

            return networkPath;
        }

        private static string MountNetworkPath(string netPath, string fileName) {
            string networkPath = netPath + "\\" + fileName;
            if(System.IO.File.Exists(networkPath))
                return MountNetworkPath(netPath, "new_" + fileName);
            return networkPath;    
        }

        private static string GetArtifactName(string artifactPath) {
            if (artifactPath == null)
                return String.Empty;
            artifactPath = artifactPath.Replace("\\", "/");
            int lastIndex = artifactPath.LastIndexOf('/');
            if (lastIndex < 0)
                return String.Empty;
            return artifactPath.Substring(lastIndex + 1);

        }

        

        
        
    }
}
